package com.loong.system.handler;

import com.loong.common.constant.SystemLetterType;
import com.loong.common.domain.Pager;
import com.loong.common.redis.RedisTools;
import com.loong.common.utils.TransformUtils;
import com.loong.global.constant.RedisKey;
import com.loong.global.dto.UserDTO;
import com.loong.system.business.SystemLetterBusiness;
import com.loong.system.common.backend.param.SystemFeedbackReplyParam;
import com.loong.system.common.backend.param.SystemLetterPageQueryParam;
import com.loong.system.common.backend.param.SystemLetterParam;
import com.loong.system.common.backend.result.SystemLetterResult;
import com.loong.system.common.forehead.param.DeleteSystemLetterForeheadParam;
import com.loong.system.common.forehead.param.SystemLetterPageQueryForeheadParam;
import com.loong.system.common.forehead.result.SystemLetterForeheadResult;
import com.loong.system.mapper.SystemLetterMapper;
import com.loong.system.mapper.SystemLetterTemplateMapper;
import com.loong.system.model.SystemLetter;
import com.loong.system.model.SystemLetterTemplate;
import com.loong.system.param.LetterTemplateConditionParam;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;

/**
 * @author LiuQun
 * @date 2020-09-29 10:52
 * 处理站内信的service
 */
@Slf4j
@Service
public class SystemLetterHandler {
    @Resource
    private SystemLetterBusiness letterBusiness;

    @Resource
    private SystemLetterTemplateMapper templateMapper;

    @Resource
    private SystemLetterMapper letterMapper;

    @Resource
    private SystemFeedbackHandler feedbackHandler;


    /**
     * 前端用户新增系统发送的站内信到数据库表中
     * @param userDTO 用户信息
     * @return 站内信结果集
     */
    public void foreheadSaveSystemLetter(UserDTO userDTO){
        //获取用户上一次拉取站内信的时间：
        Long timeObj = (Long) RedisTools.valueOperations().get(RedisKey.SYSTEM.SYNCHRONIZED_TIME + userDTO.getId());
        Date lastTime = null;
        if(ObjectUtils.isNotEmpty(timeObj)){
            lastTime = new Date(timeObj);//将时间毫秒数转化为日期
        }
        //用户拉取站内信的当前的时间
        Date nowTime = new Date();
        //当前时间减去2个月
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(nowTime);
        calendar.add(Calendar.MONTH,-2);
        //封装查询系统发送站内信的条件
        LetterTemplateConditionParam conditionParam = LetterTemplateConditionParam.builder()
                .userId(userDTO.getId())
                .userType(userDTO.getUserType())
                .userLevel(userDTO.getMemberLevelId())
                .vipLevel(userDTO.getMemberVipLevel())
                .build();

        if(ObjectUtils.isNotEmpty(lastTime)){ //表示用户拉取过站内信
            //判断用户上次拉取站内信的时间与现在的时间间隔
            long timeInterval = (nowTime.getTime()-lastTime.getTime())/(30L*24L*60L*60L*1000L);
            if(timeInterval<=2){
                //时间间隔小于2个月，则拉取上次登录时间到现在的站内信
                conditionParam.setDate(lastTime);
            }else{
                //时间间隔大于2个月，则拉取2个月前到现在的站内信
                conditionParam.setDate(calendar.getTime());
            }
        }else{
            //表示用户没有拉取过站内信，则拉取2个月前到现在的站内信
            conditionParam.setDate(calendar.getTime());
        }
        //查询属于自己的系统站内信
        List<SystemLetterTemplate> list = templateMapper.findLetterTemplates(conditionParam);
        List<SystemLetter> letterList = new ArrayList<>();//用来存放站内信内容的
        //将系统发送给自己的站内信插入到站内信表中：
        if(!CollectionUtils.isEmpty(list)){
            for (SystemLetterTemplate template : list) {
                SystemLetter letter = SystemLetter.builder()
                        .userId(userDTO.getId())
                        .userType(userDTO.getUserType())
                        .content(template.getContent())
                        .sendTime(template.getSendTime())
                        .tag(template.getTag())
                        .receiveTime(nowTime)
                        .isRead(false)   //插入到站内信表中的都是未读的
                        .letterType(SystemLetterType.SYSTEM_SEND)   //系统发送的站内信
                        .linkId(template.getId())
                        .sender(template.getSender())
                        .senderId(template.getSenderId())
                        .title(template.getTitle())
                        .build();
                letter.setCreateTime(new Date());
                letterList.add(letter);
            }
            letterBusiness.save(letterList);
        }
        //将用户拉取站内信的时间同步到Redis中
        RedisTools.valueOperations().set(RedisKey.SYSTEM.SYNCHRONIZED_TIME+userDTO.getId(),nowTime);
    }


    /**
     * 前端分页查询站内信
     * @param param 查询参数
     * @return 分页结果
     */
    public Pager<SystemLetterForeheadResult> foreheadPageQueryLetter(SystemLetterPageQueryForeheadParam param){
        param.setOrderByColumn("isRead,createTime");
        param.setAscOrDesc("asc,desc");
        Pager<SystemLetter> pager = letterBusiness.pageQuery(param, () -> letterBusiness.findLetterByParam(param));
        return TransformUtils.transformPage(pager,SystemLetterForeheadResult.class);
    }

    /**
     * 前端获取用户未读的站内信数量
     * @param userId 用户id
     * @return 数量
     */
    public Long foreheadGetUnReadLetterNum(Long userId){
        return letterBusiness.count(() -> letterBusiness.findUnReadLetter(userId));
    }

    /**
     * 前端批量删除站内信
     * @param param 站内信删除封装的参数
     */
    public void foreheadBatchDeleteLetters(DeleteSystemLetterForeheadParam param){
        List<Long> letterIdList = param.getLetterIdList();
        for (Long letterId : letterIdList) {
            letterBusiness.deleteLettersByParam(param.getUserId(),letterId);
        }
    }

    /**
     * 前端更新回复反馈类型的站内信的接收时间
     * @param userId 用户id
     */
    public void foreheadUpdateRepliedLetterReceiveTime(Long userId){
        letterMapper.updateLetterReceiveTime(userId);
    }

    /**
     * 前端更新站内信的已读状态
     * @param letterId 站内信id
     */
    public void foreheadUpdateLetterReadStatus(Long letterId){
        Date date = new Date();
        SystemLetter letter = SystemLetter.builder().isRead(true).readTime(date).build();
        letter.setId(letterId);
        letter.setLastUpdateTime(date);
        letterBusiness.updateByPrimaryKeySelective(letter);
    }

    /**
     * 前端查询站内信详情
     * @param letterId 站内信id
     * @return 站内信
     */
    public SystemLetterForeheadResult foreheadFindLetterDetailById(Long letterId){
        SystemLetter letter = letterBusiness.findById(letterId);
        if (ObjectUtils.isEmpty(letter)) return null;
        return TransformUtils.transform(letter,SystemLetterForeheadResult.class);
    }

    /**
     * 后台回复反馈时的新增站内信
     * @param letterParam 站内信参数
     */
    @Transactional
    public void saveRepliedLetter(SystemLetterParam letterParam){
        Date date = new Date();
        //新增回复反馈时的站内信
        letterParam.setCreateTime(date);
        letterParam.setSendTime(date);
        letterParam.setLetterType(0);//0表示信件类型为回复反馈
        letterParam.setIsRead(false);//阅读状态为未读
        SystemLetter letter = TransformUtils.transform(letterParam, SystemLetter.class);
        letterBusiness.save(letter);
        //更新用户反馈状态为已回复
        SystemFeedbackReplyParam replyParam = SystemFeedbackReplyParam.builder()
                .id(letter.getLinkId()) //站内信的linkId就是用户反馈的id
                .replied(true)
                .replier(letter.getSender()) //站内信的发送人就是用户反馈的回复人
                .replierId(letter.getSenderId()) //站内信的发送人id就是用户反馈的回复人id
                .replyId(letter.getId()) //站内信的主键id就是回复的id
                .lastUpdateTime(date)
                .replyTime(date)
                .build();
        feedbackHandler.updateFeedbackRepliedStatus(replyParam);
    }

    /**
     * 后台更新站内信
     * @param param 站内信参数
     */
    public void updateLetter(SystemLetterParam param){
        param.setLastUpdateTime(new Date());
        letterBusiness.updateByPrimaryKeySelective(TransformUtils.transform(param,SystemLetter.class));
    }

    /**
     * 后台批量删除站内信
     * @param idList 站内信id集合
     */
    public void batchDeleteLetter(List<Long> idList){
        letterBusiness.deleteByIds(StringUtils.join(idList,","));
    }

    /**
     * 后台分页查询数据库中的站内信
     * @param queryParam 查询参数
     * @return 站内信结果集合
     */
    public Pager<SystemLetterResult> pageQueryLetter(SystemLetterPageQueryParam queryParam){
        SystemLetterPageQueryForeheadParam param = TransformUtils.transform(queryParam, SystemLetterPageQueryForeheadParam.class);
        Pager<SystemLetter> pager = letterBusiness.pageQuery(queryParam, () -> letterBusiness.findLetterByParam(param));
        return TransformUtils.transformPage(pager,SystemLetterResult.class);
    }

    /**
     * 后台根据关联id查询已读站内信的数量
     * @param linkId 关联id
     * @return 已读站内信属性
     */
    protected Long findReadLetterNumByLinkId(Long linkId){
        return letterBusiness.count(() -> letterBusiness.findReadLetterByLinkId(linkId));
    }

    /**
     * 后台根据关联id查询是否存在该站内信
     * @param linkId 关联id
     * @return 是否存在该站内信
     */
    protected boolean existsLetterByLinkId(Long linkId){
        SystemLetter letter = letterBusiness.findBy("linkId", linkId);
        if (ObjectUtils.isNotEmpty(letter)) return true;
        return false;
    }


}
